﻿using System;
using System.Data;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace BizElements.Core
{
    /// <summary>
    /// The list of columns to be updated and expressions that compute/contain new values.
    /// <seealso cref="UpdateStatement"/>
    /// </summary>
    [Serializable]
    public sealed class UpdateList : IEnumerable, IEnumerable<UpdateExpression>
    {
        #region Members, properties, indexers.

        List<UpdateExpression> list = new List<UpdateExpression>();        

        /// <summary>
        /// Gets the number or SET expressions in this collection.
        /// </summary>
        public int Count
        {
            get { return this.list.Count; }
        }

        /// <summary>
        /// Gets the expression at the specified position.
        /// </summary>
        internal UpdateExpression this[int index]
        {
            get { return this.list[index]; }
        }

        /// <summary>
        /// Initializes a new instance of the UpdateList class.
        /// </summary>
        public UpdateList()
        { 
        }

        /// <summary>
        /// Initializes a new instance of the UpdateList class.
        /// </summary>
        /// <param name="column">First column in the UpdateList which is to be changed.</param>
        /// <param name="value">New value of the specified field. May be <b>null</b>.</param>
        /// <remarks>Initializes a new instance of the UpdateList class and sets the first expression.</remarks>
        public UpdateList(IDbColumn column, object value)
        {
            Add(column, value);
        }

        #endregion

        #region Add & Clear methods.

        /// <summary>
        /// Adds a SET expression to the list.
        /// </summary>
        /// <param name="setExpression">SET expression.</param>
        public void Add(UpdateExpression setExpression)
        {
            this.list.Add(setExpression);
        }

        /// <summary>
        /// Adds a SET expression to the list.
        /// </summary>
        /// <param name="column">Column which is to be changed. <b>Null</b> is not allowed.</param>
        /// <param name="value">New value of the specified field. May be <b>null</b>.</param>
        public void Add(IDbColumn column, object value)
        {
            if (column == null)
                throw new ArgumentNullException("column", Messages.UpdateList_ColMayNotBeNull);

            if (value == DBNull.Value)
                value = null;

            if (value != null)
                this.list.Add(UpdateExpressionFactory.Value(column, value));
            else
                this.list.Add(UpdateExpressionFactory.Null(column));
        }

        /// <summary>
        /// Adds a SET expression to the list.
        /// </summary>
        /// <param name="targetColumn">Column which is to be changed. <b>Null</b> is not allowed.</param>
        /// <param name="sourceColumn">Source column that contains the new value. <b>Null</b> is not allowed.</param>
        /// <remarks>Copies value of the source column into the target column.</remarks>
        public void Add(IDbColumn targetColumn, IDbColumn sourceColumn)
        {
            if (targetColumn == null || sourceColumn == null)
                throw new ArgumentException(Messages.UpdateList_ColMayNotBeNull);

            this.list.Add(UpdateExpressionFactory.OtherColumn(targetColumn, sourceColumn));
        }

        /// <summary>
        /// Removes all expressions from the collection.
        /// </summary>
        public void Clear()
        {
            this.list.Clear();
        }

        #endregion

        #region IEnumerable.

        /// <summary>
        /// Gets an enumerator that can iterate through UpdateList.
        /// </summary>
        public IEnumerator GetEnumerator()
        {
            return this.list.GetEnumerator();
        }

        #endregion

        #region IEnumerable<UpdateExpression> Members

        /// <summary>
        /// Gets an enumerator that can iterate through UpdateList.
        /// </summary>
        IEnumerator<UpdateExpression> IEnumerable<UpdateExpression>.GetEnumerator()
        {
            return this.list.GetEnumerator();
        }

        #endregion
    }
}